{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "68a13ecd",
   "metadata": {},
   "source": [
    "# Tutorial: Using Cohere with Elasticsearch\n",
    "\n",
    "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/elastic/elasticsearch-labs/blob/main/notebooks/integrations/cohere/cohere-elasticsearch.ipynb)\n",
    "\n",
    "This tutorial shows you how to compute embeddings with\n",
    "Cohere using the inference API and store them for efficient vector or hybrid\n",
    "search in Elasticsearch. This tutorial uses the Python Elasticsearch client\n",
    "to perform the operations.\n",
    "\n",
    "You'll learn how to:\n",
    "* create an inference endpoint for text embedding using the Cohere service,\n",
    "* create the necessary index mapping for the Elasticsearch index,\n",
    "* build an inference pipeline to ingest documents into the index together with the embeddings,\n",
    "* perform hybrid search on the data,\n",
    "* rerank search results by using Cohere's rerank model,\n",
    "* design a RAG system with Cohere's Chat API.\n",
    "\n",
    "The tutorial uses the [SciFact](https://huggingface.co/datasets/mteb/scifact) data set.\n",
    "\n",
    "Refer to [Cohere's tutorial](https://docs.cohere.com/docs/elasticsearch-and-cohere) for an example using a different data set."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7f068b1b",
   "metadata": {},
   "source": [
    "## 🧰 Requirements\n",
    "\n",
    "For this example, you will need:\n",
    "\n",
    "- An Elastic deployment with minimum **4GB machine learning node**\n",
    "   - We'll be using [Elastic Cloud](https://www.elastic.co/guide/en/cloud/current/ec-getting-started.html) for this example (available with a [free trial](https://cloud.elastic.co/registration?onboarding_token=vectorsearch&utm_source=github&utm_content=elasticsearch-labs-notebook))\n",
    "   \n",
    "- A paid [Cohere account](https://cohere.com/) is required to use the Inference API with \n",
    "the Cohere service as the Cohere free trial API usage is limited.\n",
    "\n",
    "- Python 3.7 or later."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aac02d37",
   "metadata": {},
   "source": [
    "## Install and import required packages\n",
    "\n",
    "Install Elasticsearch and Cohere:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "50940b4d",
   "metadata": {},
   "outputs": [],
   "source": [
    "!pip install elasticsearch\n",
    "!pip install cohere"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3b24d95b",
   "metadata": {},
   "source": [
    "Import the required packages:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1a5a5eeb",
   "metadata": {},
   "outputs": [],
   "source": [
    "from elasticsearch import Elasticsearch, helpers\n",
    "import cohere\n",
    "import json\n",
    "import requests\n",
    "from getpass import getpass"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3d0dacc5",
   "metadata": {},
   "source": [
    "## Create an Elasticsearch client"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "74841401",
   "metadata": {},
   "source": [
    "Now you can instantiate the Python Elasticsearch client.\n",
    "\n",
    "First provide your password and Cloud ID.\n",
    "Then create a `client` object that instantiates an instance of the `Elasticsearch` class."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "76394974",
   "metadata": {},
   "outputs": [],
   "source": [
    "# https://www.elastic.co/search-labs/tutorials/install-elasticsearch/elastic-cloud#finding-your-cloud-id\n",
    "ELASTIC_CLOUD_ID = getpass(\"Elastic Cloud ID: \")\n",
    "\n",
    "# https://www.elastic.co/search-labs/tutorials/install-elasticsearch/elastic-cloud#creating-an-api-key\n",
    "ELASTIC_API_KEY = getpass(\"Elastic API key: \")\n",
    "\n",
    "# Create the client instance\n",
    "client = Elasticsearch(\n",
    "    # For local development\n",
    "    # hosts=[\"http://localhost:9200\"]\n",
    "    cloud_id=ELASTIC_CLOUD_ID,\n",
    "    api_key=ELASTIC_API_KEY,\n",
    ")\n",
    "\n",
    "# Confirm the client has connected\n",
    "print(client.info())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3d29b809",
   "metadata": {},
   "source": [
    "## Create the inference endpoint\n",
    "\n",
    "Create the inference endpoint first. In this example, the inference endpoint \n",
    "uses Cohere's `embed-english-v3.0` model and the `embedding_type` is set to\n",
    "`byte`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ae8ae88c",
   "metadata": {},
   "outputs": [],
   "source": [
    "COHERE_API_KEY = getpass(\"Cohere API key: \")\n",
    "co = cohere.Client(api_key=COHERE_API_KEY)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6e524ce4",
   "metadata": {},
   "outputs": [],
   "source": [
    "client.inference.put_model(\n",
    "    task_type=\"text_embedding\",\n",
    "    inference_id=\"cohere_embeddings\",\n",
    "    body={\n",
    "        \"service\": \"cohere\",\n",
    "        \"service_settings\": {\n",
    "            \"api_key\": COHERE_API_KEY,\n",
    "            \"model_id\": \"embed-english-v3.0\",\n",
    "            \"embedding_type\": \"byte\",\n",
    "        },\n",
    "    },\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "884e424d",
   "metadata": {},
   "source": [
    "You can find your API keys in your Cohere dashboard under the\n",
    "[API keys section](https://dashboard.cohere.com/api-keys)."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "178c32db",
   "metadata": {},
   "source": [
    "## Create the index mapping\n",
    "\n",
    "Create the index mapping for the index that will contain the embeddings."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "35ab26b2",
   "metadata": {},
   "outputs": [],
   "source": [
    "client.indices.create(\n",
    "    index=\"cohere-embeddings\",\n",
    "    settings={\"index\": {\"default_pipeline\": \"cohere_embeddings\"}},\n",
    "    mappings={\n",
    "        \"properties\": {\n",
    "            \"text_embedding\": {\n",
    "                \"type\": \"dense_vector\",\n",
    "                \"dims\": 1024,\n",
    "                \"element_type\": \"byte\",\n",
    "            },\n",
    "            \"text\": {\"type\": \"text\"},\n",
    "            \"id\": {\"type\": \"integer\"},\n",
    "            \"title\": {\"type\": \"text\"},\n",
    "        }\n",
    "    },\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "acd3afe6",
   "metadata": {},
   "source": [
    "## Create the inference pipeline\n",
    "\n",
    "Now you have an inference endpoint and an index ready to store embeddings. The next\n",
    "step is to create an ingest pipeline that creates the embeddings using the\n",
    "inference endpoint and stores them in the index."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cec6f5c3",
   "metadata": {},
   "outputs": [],
   "source": [
    "client.ingest.put_pipeline(\n",
    "    id=\"cohere_embeddings\",\n",
    "    description=\"Ingest pipeline for Cohere inference.\",\n",
    "    processors=[\n",
    "        {\n",
    "            \"inference\": {\n",
    "                \"model_id\": \"cohere_embeddings\",\n",
    "                \"input_output\": {\n",
    "                    \"input_field\": \"text\",\n",
    "                    \"output_field\": \"text_embedding\",\n",
    "                },\n",
    "            }\n",
    "        }\n",
    "    ],\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9c5e1e7b",
   "metadata": {},
   "source": [
    "## Prepare data and insert documents\n",
    "\n",
    "This example uses the [SciFact](https://huggingface.co/datasets/mteb/scifact) data\n",
    "set that you can find on HuggingFace."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c71b8367",
   "metadata": {},
   "outputs": [],
   "source": [
    "url = \"https://huggingface.co/datasets/mteb/scifact/raw/main/corpus.jsonl\"\n",
    "\n",
    "# Fetch the JSONL data from the URL\n",
    "response = requests.get(url)\n",
    "response.raise_for_status()  # Ensure we notice bad responses\n",
    "\n",
    "# Split the content by new lines and parse each line as JSON\n",
    "data = [json.loads(line) for line in response.text.strip().split(\"\\n\") if line]\n",
    "\n",
    "# Change `_id` key to `id` as `_id` is a reserved key in Elasticsearch.\n",
    "for item in data:\n",
    "    if \"_id\" in item:\n",
    "        item[\"id\"] = item.pop(\"_id\")\n",
    "\n",
    "# Prepare the documents to be indexed\n",
    "documents = []\n",
    "for line in data:\n",
    "    data_dict = line\n",
    "    documents.append(\n",
    "        {\n",
    "            \"_index\": \"cohere-embeddings\",\n",
    "            \"_source\": data_dict,\n",
    "        }\n",
    "    )\n",
    "\n",
    "# Use the bulk endpoint to index\n",
    "helpers.bulk(client, documents)\n",
    "\n",
    "print(\"Data ingestion completed, text embeddings generated!\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9332078a",
   "metadata": {},
   "source": [
    "Your index is populated with the SciFact data and text embeddings for the text\n",
    "field."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "610035af",
   "metadata": {},
   "source": [
    "## Hybrid search\n",
    "\n",
    "Let's start querying the index!\n",
    "\n",
    "The code below performs a hybrid search. The `kNN` query computes the relevance\n",
    "of search results based on vector similarity using the `text_embedding` field.\n",
    "The lexical search query uses BM25 retrieval to compute keyword similarity on\n",
    "the `title` and `text` fields."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ab735ef0",
   "metadata": {},
   "outputs": [],
   "source": [
    "query = \"What is biosimilarity?\"\n",
    "\n",
    "response = client.search(\n",
    "    index=\"cohere-embeddings\",\n",
    "    size=100,\n",
    "    knn={\n",
    "        \"field\": \"text_embedding\",\n",
    "        \"query_vector_builder\": {\n",
    "            \"text_embedding\": {\n",
    "                \"model_id\": \"cohere_embeddings\",\n",
    "                \"model_text\": query,\n",
    "            }\n",
    "        },\n",
    "        \"k\": 10,\n",
    "        \"num_candidates\": 50,\n",
    "    },\n",
    "    query={\"multi_match\": {\"query\": query, \"fields\": [\"text\", \"title\"]}},\n",
    ")\n",
    "\n",
    "raw_documents = response[\"hits\"][\"hits\"]\n",
    "\n",
    "# Display the first 10 results\n",
    "for document in raw_documents[0:10]:\n",
    "    print(\n",
    "        f'Title: {document[\"_source\"][\"title\"]}\\nText: {document[\"_source\"][\"text\"]}\\n'\n",
    "    )\n",
    "\n",
    "# Format the documents for ranking\n",
    "documents = []\n",
    "for hit in response[\"hits\"][\"hits\"]:\n",
    "    documents.append(hit[\"_source\"][\"text\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "153ce2d5",
   "metadata": {},
   "source": [
    "## Rerank search results\n",
    "\n",
    "To combine the results more effectively, use \n",
    "[Cohere's Rerank v3](https://docs.cohere.com/docs/rerank-2) model through the\n",
    "inference API to provide a more precise semantic reranking of the results.\n",
    "\n",
    "Create an inference endpoint with your Cohere API key and the used model name as\n",
    "the `model_id` (`rerank-english-v3.0` in this example)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "886c4d15",
   "metadata": {},
   "outputs": [],
   "source": [
    "client.inference.put_model(\n",
    "    task_type=\"rerank\",\n",
    "    inference_id=\"cohere_rerank\",\n",
    "    body={\n",
    "        \"service\": \"cohere\",\n",
    "        \"service_settings\": {\n",
    "            \"api_key\": COHERE_API_KEY,\n",
    "            \"model_id\": \"rerank-english-v3.0\",\n",
    "        },\n",
    "        \"task_settings\": {\n",
    "            \"top_n\": 10,\n",
    "        },\n",
    "    },\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ebf82d4a",
   "metadata": {},
   "source": [
    "Rerank the results using the new inference endpoint."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "id": "296b6f2f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Title: Interchangeability of Biosimilars: A European Perspective\n",
      "Text: Many of the best-selling ‘blockbuster’ biological medicinal products are, or will soon be, facing competition from similar biological medicinal products (biosimilars) in the EU. Biosimilarity is based on the comparability concept, which has been used successfully for several decades to ensure close similarity of a biological product before and after a manufacturing change. Over the last 10 years, experience with biosimilars has shown that even complex biotechnology-derived proteins can be copied successfully. Most best-selling biologicals are used for chronic treatment. This has triggered intensive discussion on the interchangeability of a biosimilar with its reference product, with the main concern being immunogenicity. We explore the theoretical basis of the presumed risks of switching between a biosimilar and its reference product and the available data on switches. Our conclusion is that a switch between comparable versions of the same active substance approved in accordance with EU legislation is not expected to trigger or enhance immunogenicity. On the basis of current knowledge, it is unlikely and very difficult to substantiate that two products, comparable on a population level, would have different safety or efficacy in individual patients upon a switch. Our conclusion is that biosimilars licensed in the EU are interchangeable.\n",
      "\n",
      "Title: siRNA specificity searching incorporating mismatch tolerance data.\n",
      "Text: UNLABELLED Artificially synthesized short interfering RNAs (siRNAs) are widely used in functional genomics to knock down specific target genes. One ongoing challenge is to guarantee that the siRNA does not elicit off-target effects. Initial reports suggested that siRNAs were highly sequence-specific; however, subsequent data indicates that this is not necessarily the case. It is still uncertain what level of similarity and other rules are required for an off-target effect to be observed, and scoring schemes have not been developed to look beyond simple measures such as the number of mismatches or the number of consecutive matching bases present. We created design rules for predicting the likelihood of a non-specific effect and present a web server that allows the user to check the specificity of a given siRNA in a flexible manner using a combination of methods. The server finds potential off-target matches in the corresponding RefSeq database and ranks them according to a scoring system based on experimental studies of specificity. AVAILABILITY The server is available at http://informatics-eskitis.griffith.edu.au/SpecificityServer.\n",
      "\n",
      "Title: ImmTACs for targeted cancer therapy: Why, what, how, and which.\n",
      "Text: Overcoming immunosuppression and activating a cytotoxic T cell response has the potential to halt the progression of cancer and, in some circumstances, eradicate it. Designing therapeutic interventions that achieve this goal has proven challenging, but now a greater understanding of the complexities of immune responses is beginning to produce some notable breakthroughs. ImmTACs (immune-mobilising monoclonal TCRs against cancer) are a new class of bispecific reagents, based on soluble monoclonal T cell receptors, which have been engineered to possess extremely high affinity for cognate tumour antigen. In this way, ImmTACs overcome the problem of low affinity tumour-specific T cells imposed by thymic selection and provide access to the large number of antigens presented as peptide-HLA complexes. Once bound to tumour cells the anti-CD3 effector end of the ImmTAC drives recruitment of polyclonal T cells to the tumour site, leading to a potent redirected T cell response and tumour cell destruction. Extensive in vitro testing coupled with promising early clinical data has provided an enhanced appreciation of ImmTAC function in vivo and indicates their potential therapeutic benefit in terms of a durable response and ultimately the breaking of T cell tolerance. This review introduces ImmTACs in the context of immunotherapy, and outlines their design, construction and mechanism of action, as well as examining target selection and aspects of preclinical safety testing.\n",
      "\n",
      "Title: Coming soon to a Wal-Mart near you\n",
      "Text: According to the Web site of the Association for Automatic Identification and Data Capture Technologies [http://www.aimglobal.org/technologies/rfid], \"radio frequency identification (RFID) technology is an automatic way to collect product, place, and time or transaction data quickly and easily without human intervention or error. \" With the ability to track everything from crates of disposable razors to individual peanut-butter jars on the store shelves, RFID technology offers the potential of \"real-time supply chain visibility. \" Promoters of RFID technology feel [C. Humer, 2003] that \"RF tags are to this decade what the Internet was to the 1990's-a promise of radical change in the way business is done. \" However, before the full potential of RFID technology can be realized, several hurdles need to be overcome: reliability, cost, lack of standards, and security. As these hurdles gradually diminish, Wal-Mart publicly embraces the technology.\n",
      "\n",
      "Title: Dynamic Helix Interactions in Transmembrane Signaling\n",
      "Text: Studying how protein transmembrane domains transmit signals across membranes is beset by unique challenges. Here, we discuss the circumstances that have led to success and reflect on what has been learned from these examples. Such efforts suggest that some of the most interesting properties of transmembrane helix interactions may be the least amenable to study by current techniques.\n",
      "\n",
      "Title: Ciliary Extracellular Vesicles: Txt Msg Organelles\n",
      "Text: Cilia are sensory organelles that protrude from cell surfaces to monitor the surrounding environment. In addition to its role as sensory receiver, the cilium also releases extracellular vesicles (EVs). The release of sub-micron sized EVs is a conserved form of intercellular communication used by all three kingdoms of life. These extracellular organelles play important roles in both short and long range signaling between donor and target cells and may coordinate systemic responses within an organism in normal and diseased states. EV shedding from ciliated cells and EV–cilia interactions are evolutionarily conserved phenomena, yet remarkably little is known about the relationship between the cilia and EVs and the fundamental biology of EVs. Studies in the model organisms Chlamydomonas and Caenorhabditis elegans have begun to shed light on ciliary EVs. Chlamydomonas EVs are shed from tips of flagella and are bioactive. Caenorhabditis elegans EVs are shed and released by ciliated sensory neurons in an intraflagellar transport-dependent manner. Caenorhabditis elegans EVs play a role in modulating animal-to-animal communication, and this EV bioactivity is dependent on EV cargo content. Some ciliary pathologies, or ciliopathies, are associated with abnormal EV shedding or with abnormal cilia–EV interactions. Until the 21st century, both cilia and EVs were ignored as vestigial or cellular junk. As research interest in these two organelles continues to gain momentum, we envision a new field of cell biology emerging. Here, we propose that the cilium is a dedicated organelle for EV biogenesis and EV reception. We will also discuss possible mechanisms by which EVs exert bioactivity and explain how what is learned in model organisms regarding EV biogenesis and function may provide insight to human ciliopathies.\n",
      "\n",
      "Title: How nascent phagosomes mature to become phagolysosomes.\n",
      "Text: Phagocytosis mediates the clearance of apoptotic bodies and also the elimination of microbial pathogens. The nascent phagocytic vacuole formed upon particle engulfment lacks microbicidal and degradative activity. These capabilities are acquired as the phagosome undergoes maturation; a progressive remodeling of its membrane and contents that culminates in the formation of phagolysosomes. Maturation entails orderly sequential fusion of the phagosomal vacuole with specialized endocytic and secretory compartments. Concomitantly, the phagosomal membrane undergoes both inward and outward vesiculation and tubulation followed by fission, thereby recycling components and maintaining its overall size. Here, we summarize what is known about the molecular machinery that governs this complex metamorphosis of phagosome maturation.\n",
      "\n",
      "Title: What influences government adoption of vaccines in developing countries? A policy process analysis.\n",
      "Text: This paper proposes a framework for examining the process by which government consideration and adoption of new vaccines takes place, with specific reference to developing country settings. The cases of early Hepatitis B vaccine adoption in Taiwan and Thailand are used to explore the relevance of explanatory factors identified in the literature as well as the need to go beyond a variable-centric focus by highlighting the role of policy context and process in determining the pace and extent of adoption. The cases suggest the feasibility and importance of modeling 'causal diversity'-the complex set of necessary and sufficient conditions leading to particular decisional outcomes-in a broad range of country contexts. A better understanding of the lenses through which government decision-makers filter information, and of the arenas in which critical decisions are shaped and taken, may assist both analysts (in predicting institutionalization of new vaccines) and advocates (in crafting targeted strategies to accelerate their diffusion).\n",
      "\n",
      "Title: Aire regulates negative selection of organ-specific T cells\n",
      "Text: Autoimmune polyendocrinopathy syndrome type 1 is a recessive Mendelian disorder resulting from mutations in a novel gene, AIRE, and is characterized by a spectrum of organ-specific autoimmune diseases. It is not known what tolerance mechanisms are defective as a result of AIRE mutation. By tracing the fate of autoreactive CD4+ T cells with high affinity for a pancreatic antigen in transgenic mice with an Aire mutation, we show here that Aire deficiency causes almost complete failure to delete the organ-specific cells in the thymus. These results indicate that autoimmune polyendocrinopathy syndrome 1 is caused by failure of a specialized mechanism for deleting forbidden T cell clones, establishing a central role for this tolerance mechanism.\n",
      "\n",
      "Title: Parallel processing in the mammalian retina\n",
      "Text: Our eyes send different 'images' of the outside world to the brain — an image of contours (line drawing), a colour image (watercolour painting) or an image of moving objects (movie). This is commonly referred to as parallel processing, and starts as early as the first synapse of the retina, the cone pedicle. Here, the molecular composition of the transmitter receptors of the postsynaptic neurons defines which images are transferred to the inner retina. Within the second synaptic layer — the inner plexiform layer — circuits that involve complex inhibitory and excitatory interactions represent filters that select 'what the eye tells the brain'.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "response = client.inference.inference(\n",
    "    inference_id=\"cohere_rerank\",\n",
    "    body={\n",
    "        \"query\": query,\n",
    "        \"input\": documents,\n",
    "        \"task_settings\": {\"return_documents\": False},\n",
    "    },\n",
    ")\n",
    "\n",
    "# Reconstruct the input documents based on the index provided in the rereank response\n",
    "ranked_documents = []\n",
    "for document in response.body[\"rerank\"]:\n",
    "    ranked_documents.append(\n",
    "        {\n",
    "            \"title\": raw_documents[int(document[\"index\"])][\"_source\"][\"title\"],\n",
    "            \"text\": raw_documents[int(document[\"index\"])][\"_source\"][\"text\"],\n",
    "        }\n",
    "    )\n",
    "\n",
    "# Print the top 10 results\n",
    "for document in ranked_documents[0:10]:\n",
    "    print(f\"Title: {document['title']}\\nText: {document['text']}\\n\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9539ff47",
   "metadata": {},
   "source": [
    "## Retrieval Augmented Generation (RAG) with Cohere and Elasticsearch\n",
    "\n",
    "RAG is a method for generating text using additional information fetched from an\n",
    "external data source. With the ranked results, you can build a RAG system on\n",
    "top of what you created with \n",
    "[Cohere's Chat API](https://docs.cohere.com/docs/chat-api).\n",
    "\n",
    "Pass in the retrieved documents and the query to receive a grounded response\n",
    "using Cohere's newest generative model \n",
    "[Command R+](https://docs.cohere.com/docs/command-r-plus).\n",
    "\n",
    "Then pass in the query and the documents to the Chat API, and print out the\n",
    "response."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "id": "39badebf",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Query: What is biosimilarity?\n",
      "Response: Biosimilarity is based on the comparability concept, which has been used successfully for several decades to ensure close similarity of a biological product before and after a manufacturing change. Over the last 10 years, experience with biosimilars has shown that even complex biotechnology-derived proteins can be copied successfully.\n",
      "Sources:\n",
      "Interchangeability of Biosimilars: A European Perspective: Many of the best-selling ‘blockbuster’ biological medicinal products are, or will soon be, facing competition from similar biological medicinal products (biosimilars) in the EU. Biosimilarity is based on the comparability concept, which has been used successfully for several decades to ensure close similarity of a biological product before and after a manufacturing change. Over the last 10 years, experience with biosimilars has shown that even complex biotechnology-derived proteins can be copied successfully. Most best-selling biologicals are used for chronic treatment. This has triggered intensive discussion on the interchangeability of a biosimilar with its reference product, with the main concern being immunogenicity. We explore the theoretical basis of the presumed risks of switching between a biosimilar and its reference product and the available data on switches. Our conclusion is that a switch between comparable versions of the same active substance approved in accordance with EU legislation is not expected to trigger or enhance immunogenicity. On the basis of current knowledge, it is unlikely and very difficult to substantiate that two products, comparable on a population level, would have different safety or efficacy in individual patients upon a switch. Our conclusion is that biosimilars licensed in the EU are interchangeable.\n"
     ]
    }
   ],
   "source": [
    "response = co.chat(message=query, documents=ranked_documents, model=\"command-r-plus\")\n",
    "\n",
    "source_documents = []\n",
    "for citation in response.citations:\n",
    "    for document_id in citation.document_ids:\n",
    "        if document_id not in source_documents:\n",
    "            source_documents.append(document_id)\n",
    "\n",
    "print(f\"Query: {query}\")\n",
    "print(f\"Response: {response.text}\")\n",
    "print(\"Sources:\")\n",
    "for document in response.documents:\n",
    "    if document[\"id\"] in source_documents:\n",
    "        print(f\"{document['title']}: {document['text']}\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3.12.3 64-bit",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.3"
  },
  "vscode": {
   "interpreter": {
    "hash": "b0fa6594d8f4cbf19f97940f81e996739fb7646882a419484c72d19e05852a7e"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
